from io import BytesIO
from fastapi.security import OAuth2PasswordRequestForm
from fastapi import APIRouter, Depends, Request, HTTPException, status
from fastapi.responses import StreamingResponse
from typing import Optional, List, Any
from sqlalchemy import delete
from sqlalchemy.orm import joinedload
from sqlalchemy.future import select
from sqlmodel.ext.asyncio.session import AsyncSession
from schemas.common import RETURN, ListResponse, ListRequest
from captcha.image import ImageCaptcha
from fastapi_limiter.depends import RateLimiter
from fastapi_cache.decorator import cache

from core.Depend import check_token, has_permission
from database.mysql import get_async_session
from utils import util
from utils.jwtToken import verify_password, generate_token, refresh_Token, get_password_hash

import models.Base as BaseModel
import models.admin.system.Admin as AdminModel
import models.admin.system.Dept as DeptModel
import models.admin.system.Role as RoleModel
import models.admin.system.Link as LinkModel
import models.admin.system.Menu as MenuModel
from routers.admin.common import assembl_routes

import json
import time

from utils.util import random_num
from server.Base import BaseServer
from server.admin.SystemServer import SystemServer
from core.Config import settings
from routers.admin.common import convert_filter_values

router = APIRouter(prefix="/admin", tags=["管理员管理"])
dataLimit = False

@router.post("/getAccessToken",summary="获取token",response_model=BaseModel.Token)
async def login_for_access_token(
    form_data: OAuth2PasswordRequestForm = Depends(),
    session: AsyncSession = Depends(get_async_session)
) -> BaseModel.Token:
    statement = select(AdminModel.Admin).where(AdminModel.Admin.userName == form_data.username)
    result = await session.exec(statement)
    admin_user:AdminModel.Admin = result.scalars().first()
    if admin_user is None or  admin_user.status == BaseModel.StatusTypeEnum.ABNORMAL:
        raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="Incorrect username or password",
                headers={"WWW-Authenticate": "Bearer"},
            )
    token = generate_token(form_data.username,settings.SESSION_MAX_AGE)
    return BaseModel.Token(access_token=token['accessToken'], token_type="bearer")

# 获取验证码 配置接口请求速率 5秒2次 【使用得是redis缓存】
@router.get("/get_captcha", dependencies=[Depends(RateLimiter(times=2, seconds=5))],
            summary="获取验证码",response_model=RETURN[Any])
async def get_captcha(req: Request,  ):
    captcha_text = random_num(4)
    # captcha_text 转为字符串
    req.session['captcha'] = str(captcha_text)
    print("captcha_text",captcha_text)
    print("----------------------------------------")
    image = ImageCaptcha(height=38,width=120,font_sizes=[24,28,30]).generate_image(captcha_text)
    image_stream = BytesIO()
    image.save(image_stream, format="PNG")
    image_stream.seek(0)
    return StreamingResponse(image_stream, media_type="image/png")


# 登录
@router.post("/login",summary="管理员登录",response_model=RETURN[Optional[AdminModel.login_result]])
async def login(login: AdminModel.login,req: Request , session: AsyncSession = Depends(get_async_session)):
    # 获取验证码
    captcha = req.session.get("captcha", None)  # 使用 pop 来获取并删除验证码
    print("captcha",captcha)
    # if captcha != login.verifyCode:
    #     return RETURN.fail("验证码错误")
    # 验证账户
    statement = select(AdminModel.Admin).where(AdminModel.Admin.userName == login.userName)
    result = await session.exec(statement)
    admin_user: AdminModel.Admin = result.scalars().first()
    if admin_user is None:
        return RETURN.fail("用户不存在")
    
    if admin_user.status == BaseModel.StatusTypeEnum.ABNORMAL:
        return RETURN.fail("账户已被禁用")
    
    # 验证密码
    if verify_password(login.password,admin_user.password):
        # 生成token
        token = generate_token(login.userName,settings.SESSION_MAX_AGE)
        admin_user.loginip = util.get_ip(req)
        admin_user.logintime = time.time()
        session.add(admin_user)
   
        #查询用户角色
        role_statement = select(RoleModel.Role).join(LinkModel.Admin_Role_Link).where(LinkModel.Admin_Role_Link.admin_id == admin_user.id)
        role_result = await session.exec(role_statement)
        all_roles = role_result.scalars().all()
        roles = [role.code for role in all_roles]

        role_ids = [role.id for role in all_roles]
        if 1 in role_ids:
            admin_ids = [1]
        else:
            # 递归查询role_ids下面的所有子角色id
            async def collect_child_ids(role_id):
                child_ids = set()
                statement = select(RoleModel.Role).where(RoleModel.Role.parent_id == role_id)
                result = await session.exec(statement)
                children = result.scalars().all()
                for child in children:
                    child_ids.add(child.id)
                    await collect_child_ids(child.id)
                return child_ids
            # 循环role_ids，查询所有子角色id
            for role_id in role_ids:
                child_ids = await collect_child_ids(role_id)
                role_ids.extend(child_ids)
            
            # 获取到所有角色的权限ids,并且去重
            menu_statement = select(LinkModel.Admin_Role_Link).where(LinkModel.Admin_Role_Link.role_id.in_(role_ids))
            role_menu_result = await session.exec(menu_statement)
            role_menus = role_menu_result.scalars().all()
            admin_ids = [role_menu.admin_id for role_menu in role_menus]
            # menu_ids = List(set(menu_ids))

        # 缓存用户信息，roles也需要缓存进入 
        admin:AdminModel.redis_admin = AdminModel.redis_admin(admin= admin_user, admin_ids=admin_ids)
        await req.app.state.cache.set(f"{login.userName}:user", json.dumps(admin.model_dump()))

        data = AdminModel.login_result(
                username=admin_user.userName,
                nickname=admin_user.nickName,
                roles=roles,
                accessToken=token['accessToken'], 
                refreshToken=token['refreshToken'], 
                expires=token['expires'],
                avatar=admin_user.avatar
                )
        
        # 记录登录日志
        Admin_Login_Record = AdminModel.Admin_Login_Record(
            admin_id=admin_user.id,
            ip= util.get_ip(req),
            admin_name=admin_user.userName,
            useragent=req.headers.get("user-agent"),
            channels="web",
            desc="登录成功"
        )
        session.add(Admin_Login_Record)
        await session.commit()
        return RETURN.success("登录成功",data)
    else:
        # 记录登录日志
        Admin_Login_Record = AdminModel.Admin_Login_Record(
            admin_id=admin_user.id,
            ip= util.get_ip(req),
            admin_name=admin_user.userName,
            useragent=req.headers.get("user-agent"),
            status=BaseModel.StatusTypeEnum.ABNORMAL,
            channels="web",
            desc="登录失败"
        )

        session.add(Admin_Login_Record)
        await session.commit()

    return RETURN.fail("账号密码错误")

# 刷新token
@router.post("/refresh_token",summary="刷新token",response_model=RETURN[Any])
async def refresh_token(refreshToken: AdminModel.refresh_token, user: AdminModel.redis_admin = Depends(check_token)):
    token = await refresh_Token(refreshToken.refreshToken)
    return RETURN.success(data=token)


# 1.增加管理员
@router.post("/add",summary="管理员添加",response_model=RETURN[Any])
async def add(user: AdminModel.create_admin,session: AsyncSession = Depends(get_async_session),adminuser:AdminModel.redis_admin = Depends(has_permission("system_admin_user_add"))):
    #判断 userName 或者 mobile 是否存在
    state = select(AdminModel.Admin).where(AdminModel.Admin.userName == user.userName)
    result = await session.exec(state)
    obj = result.scalars().first()
    if obj:
        return RETURN.fail("用户名已存在")
    
    state = select(AdminModel.Admin).where(AdminModel.Admin.mobile == user.mobile)
    result = await session.exec(state)
    obj = result.scalars().first()
    if obj:
        return RETURN.fail("手机号已存在")
    
    state = select(DeptModel.Department).where(DeptModel.Department.id == user.department_id)
    result = await session.exec(state)
    obj = result.scalars().first()
    if not obj:
        return RETURN.fail("部门不存在")

    user.password =  get_password_hash(user.password)
    await BaseServer(AdminModel.Admin).create(user.dict())
    return RETURN.success("添加成功")

# 2.删除管理员
@router.delete("/delete",summary="管理员删除",response_model=RETURN[Any])
async def admin_delete(id: int,user:AdminModel.redis_admin = Depends(has_permission("system_admin_user_del"))):
    if id == 1:
        return RETURN.fail("超级管理员角色不允许删除")
    await BaseServer(AdminModel.Admin).delete(id)
    return RETURN.success("删除成功")

# 3.修改管理员
@router.put("/update",summary="管理员修改",response_model=RETURN[Any])
async def update(user: AdminModel.edit_admin,session: AsyncSession = Depends(get_async_session),adminuser:AdminModel.redis_admin = Depends(has_permission("system_admin_user_edit"))):
    state = select(AdminModel.Admin).where(AdminModel.Admin.mobile == user.mobile).where(AdminModel.Admin.id != user.id)
    result = await session.exec(state)
    obj = result.scalars().first()
    if obj:
        return RETURN.fail("手机号已存在")
    if user.department_id != 0:
        state = select(DeptModel.Department).where(DeptModel.Department.id == user.department_id)
        result = await session.exec(state)
        obj = result.scalars().first()
        if not obj:
            return RETURN.fail("部门不存在")
    
    # 如果department_id 为0，删除该字段
    if user.department_id == 0:
        user.department_id = None
    # 如果密码不为空，加密密码
    if user.password:
        user.password = get_password_hash(user.password)
    
    # 如果密码为空，删除该字段
    if not user.password:
        del user.password

    # 如果头像为空，删除该字段
    if not user.avatar:
        del user.avatar

    await BaseServer(AdminModel.Admin).update(user.dict())
    return RETURN.success("修改成功")

# 4.查询管理员
@router.post("/list",summary="管理员列表",response_model=RETURN[ListResponse[Any]])
async def list(request:ListRequest,user:AdminModel.redis_admin = Depends(has_permission("system_admin_user_list"))):
    fields = ["id","nickName","mobile","loginip","userName","avatar","logintime","status","sex","createtime","remark","email"]
    relations = {
        "department": ["id", "name"]
    }
    # 查询部门下的所有子部门，进行角色查询
    if request.filter:
        for item in request.filter:
            if item.field == "department_id":
                dept_ids = await SystemServer(DeptModel.Department).get_dept_child_ids(item.value)
                item.operator = "in"
                item.value = dept_ids

    conversion_map = {
        "sex": AdminModel.SexEnum,
        "status": BaseModel.StatusTypeEnum
    }

    request.filter = await convert_filter_values(conversion_map,request.filter,dataLimit,user)
    # ,relations=relations
    data = await BaseServer(AdminModel.Admin).list(request,fields=fields,relations=relations)
    return RETURN.success("查询成功",data)

# 批量删除
@router.delete("/batch_delete",summary="管理员批量删除",response_model=RETURN[Any])
async def batch_delete(ids: List[int],user:AdminModel.redis_admin = Depends(has_permission("system_admin_user_batch_delete"))):
    await BaseServer(AdminModel.Admin).batch_delete(ids)
    return RETURN.success("删除成功")

# 获取当前管理员信息
@router.get("/info",summary="管理员信息",response_model=RETURN[Any])
async def get(user:AdminModel.redis_admin = Depends(check_token)):
    fields = ["id","mobile","nickName","userName","avatar","email"]
    user = await BaseServer(AdminModel.Admin).get(user.admin.id,fields = fields)
    return RETURN.success("查询成功",user)


# 查询id管理员 所有用的角色id
@router.get("/roles",summary="管理员角色",response_model=RETURN[Any])
async def roles(userId: int, session: AsyncSession = Depends(get_async_session),user:AdminModel.redis_admin = Depends(has_permission("system_admin_user_roles"))):
    statement = select(RoleModel.Role.id).join(AdminModel.Admin_Role_Link).where(AdminModel.Admin_Role_Link.admin_id == userId)
    result = await session.exec(statement)
    roles = result.scalars().all()
    return RETURN.success("查询成功",roles)

# 修改管理员状态
@router.put("/status",summary="管理员状态",response_model=RETURN[Any])
async def status(id: int, status: int,user:AdminModel.redis_admin = Depends(has_permission("system_admin_user_status"))):
    await BaseServer(AdminModel.Admin).change_status(id, status)
    return RETURN.success("修改成功")

# 分配角色
@router.post("/assign",summary="管理员分配角色",response_model=RETURN[Any])
async def assign(params:AdminModel.assign_params, session: AsyncSession = Depends(get_async_session),user:AdminModel.redis_admin = Depends(has_permission("system_admin_user_assign"))):
    # 先删除原有的角色
    delete_statement = delete(AdminModel.Admin_Role_Link).where(AdminModel.Admin_Role_Link.admin_id == params.id)
    await session.exec(delete_statement)
    await session.commit()
    # # 再添加新的角色
    add_data = [AdminModel.Admin_Role_Link(admin_id=params.id, role_id=roleId) for roleId in params.roleIds]
    session.add_all(add_data)
    await session.commit()

    return RETURN.success("分配成功")


# 重置密码
@router.post("/reset_password",summary="管理员重置密码",response_model=RETURN[Any])
async def reset_password(id:int, password: str, session: AsyncSession = Depends(get_async_session),user:AdminModel.redis_admin = Depends(has_permission("system_admin_user_rest_password"))):
    state = select(AdminModel.Admin).where(AdminModel.Admin.id == id)
    result = await session.exec(state)
    user = result.scalars().first()
    if user is None:
        return RETURN.fail("用户不存在")
    user.password = get_password_hash(password)
    session.add(user)
    session.commit()
    return RETURN.success("重置成功")


# 更新头像，base64格式
@router.post("/update_avatar",summary="管理员更新头像",response_model=RETURN[Any])
async def update_avatar(id: int,avatar: str,session: AsyncSession = Depends(get_async_session),user:AdminModel.redis_admin = Depends(has_permission("system_admin_user_update_avatar"))):
    state = select(AdminModel.Admin).where(AdminModel.Admin.id == id)
    result = await session.exec(state)
    user = result.scalars().first()
    if user is None:
        return RETURN.fail("用户不存在")
    user.avatar = avatar
    session.add(user)
    await session.commit()
    return RETURN.success("更新成功")

# 6.获取异步路由
@router.get("/async_routes",summary="获取异步路由",response_model=RETURN[Any])
async def async_routes(req: Request, user: AdminModel.redis_admin = Depends(check_token),session: AsyncSession = Depends(get_async_session)):
    # 获取角色
    statement = select(RoleModel.Role).join(AdminModel.Admin_Role_Link).where(AdminModel.Admin_Role_Link.admin_id == user.admin.id)
    result = await session.exec(statement)
    roles = result.scalars().all()
    role_ids = [role.id for role in roles]


    # 如果role_ids 包含id为1的超级管理员，直接返回所有路由
    if 1 in role_ids:
        menu_statement = select(MenuModel.Menu).options(joinedload(MenuModel.Menu.roles))  # 确保加载 roles
    else:
        # TODO:获取角色对应的菜单
        menu_statement = select(MenuModel.Menu).join(RoleModel.Role_Menu_Link).options(joinedload(MenuModel.Menu.roles)).where(RoleModel.Role_Menu_Link.role_id.in_(role_ids))

    menu_result = await session.exec(menu_statement)
    menus = menu_result.unique().scalars().all()

    # TODO:redis缓存当前用户的菜单
    cache_menus = []
    for menu in menus:
        if menu.menu_type == MenuModel.MenuTypeEnum.BUTTON:
            cache_menus.append(menu.auths)
    await req.app.state.cache.set(f"{user.admin.userName}:auths", json.dumps(cache_menus))
    routes_result = await assembl_routes(menus)
    return RETURN.success("查询成功",routes_result)


# 获取当前用户代办事项
@router.get("/todo",summary="代办事项",response_model=RETURN[Any])
@cache(expire=60)
async def todo(user: AdminModel.redis_admin = Depends(check_token)):
    data = [
            {
                "key": "1",
                "name": "通知",
                "list": [],
                "emptyText": "暂无通知"
            },
            {
                "key": "2",
                "name": "消息",
                "list": [
                    {
                        "avatar": "https://xiaoxian521.github.io/hyperlink/svg/smile1.svg",
                        "title": "小铭 评论了你",
                        "description": "诚在于心，信在于行，诚信在于心行合一。",
                        "datetime": "今天",
                        "type": "2"
                    },
                    {
                        "avatar": "https://xiaoxian521.github.io/hyperlink/svg/smile2.svg",
                        "title": "李白 回复了你",
                        "description": "长风破浪会有时，直挂云帆济沧海。",
                        "datetime": "昨天",
                        "type": "2"
                    },
                    {
                        "avatar": "https://xiaoxian521.github.io/hyperlink/svg/smile5.svg",
                        "title": "标题",
                        "description":
                        "请将鼠标移动到此处，以便测试超长的消息在此处将如何处理。本例中设置的描述最大行数为2，超过2行的描述内容将被省略并且可以通过tooltip查看完整内容",
                        "datetime": "时间",
                        "type": "2"
                    },
                    {
                        "avatar": "https://xiaoxian521.github.io/hyperlink/svg/smile5.svg",
                        "title": "新增标题",
                        "description":
                        "请将鼠标移动到此处，以便测试超长的消息在此处将如何处理。本例中设置的描述最大行数为2，超过2行的描述内容将被省略并且可以通过tooltip查看完整内容",
                        "datetime": "时间",
                        "type": "2"
                    }
                ],
                "emptyText": "暂无消息"
            },
            {
                "key": "3",
                "name": "待办",
                "list": [
                    {
                        "avatar": "",
                        "title": "第三方紧急代码变更",
                        "description":
                        "小林提交于 2024-05-10，需在 2024-05-11 前完成代码变更任务",
                        "datetime": "",
                        "extra": "马上到期",
                        "status": "danger",
                        "type": "3"
                    },
                    {
                        "avatar": "",
                        "title": "版本发布",
                        "description": "指派小铭于 2024-06-18 前完成更新并发布",
                        "datetime": "",
                        "extra": "已耗时 8 天",
                        "status": "warning",
                        "type": "3"
                    },
                    {
                        "avatar": "",
                        "title": "新功能开发",
                        "description": "开发多租户管理",
                        "datetime": "",
                        "extra": "进行中",
                        "type": "3"
                    },
                    {
                        "avatar": "",
                        "title": "任务名称",
                        "description": "任务需要在 2030-10-30 10:00 前启动",
                        "datetime": "",
                        "extra": "未开始",
                        "status": "info",
                        "type": "3"
                    }
                ],
                "emptyText": "暂无待办"
            }
    ]
    return RETURN.success("查询成功",data)